package cn.sc.summer.gateway.filter;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.sc.summer.gateway.context.GatewayContext;
import cn.sc.summer.gateway.util.IPUtil;
import com.alibaba.fastjson.JSONObject;
import cn.sc.summer.constant.gateway.GatewayConstant;
import cn.sc.summer.constant.rabbit.RabbitConstant;
import cn.sc.summer.constant.token.TokenConstant;
import cn.sc.summer.rabbitmq.builder.RabbitBuilder;
import cn.sc.summer.rabbitmq.builder.RabbitMessageBuilderDirector;
import cn.sc.summer.rabbitmq.po.GatewayLog;
import cn.sc.summer.token.po.UserDetailX;
import cn.sc.summer.token.util.UserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 类名：拦截返回数据, 修改返回数据
 *
 * @author a-xin
 * @date 2024/2/5 15:32
 */
@Slf4j
@Component
public class ResponseGlobalFilter implements GlobalFilter, Ordered {

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Override
    public int getOrder() {
        return -2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        GatewayLog gatewayLog = createGatewayLog(exchange);
        return chain.filter(exchange.mutate().response(originalResponse).build()).then(Mono.fromRunnable(() -> {
            if (!gatewayLog.getReqUri().endsWith(TokenConstant.SERVER_SWAGGER)) {
                JSONObject message = new RabbitMessageBuilderDirector(new RabbitBuilder()).build();
                message.put("message", JSONObject.toJSONString(gatewayLog));
                rabbitTemplate.convertAndSend(
                        RabbitConstant.GATEWAY_LOG_EXCHANGE,
                        RabbitConstant.GATEWAY_LOG_ROUTING_KEY,
                        message.toJSONString());
            }
        }));

    }

    /**
     * 创建网关日志类
     *
     * @param exchange 网关交换机
     * @return 日志类对象
     */
    private GatewayLog createGatewayLog(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();

        GatewayContext gatewayContext = new GatewayContext();
        Object obj = exchange.getAttributes().get(GatewayContext.CACHE_GATEWAY_CONTEXT);
        if (obj instanceof GatewayContext) {
            gatewayContext = (GatewayContext) obj;
        }

        GatewayLog gatewayLog = new GatewayLog();
        gatewayLog.setId(IdUtil.simpleUUID());
        gatewayLog.setCreateTime(new Date());

        gatewayLog.setReqUri(path);
        gatewayLog.setReqMethod(request.getMethod().toString());
        gatewayLog.setReqIp(IPUtil.getIpAddr(request));
        gatewayLog.setReqParams(gatewayContext.getFormData().toString());
        HttpHeaders headers = request.getHeaders();
        gatewayLog.setReqHeaders(headers.toString());
        String requestType = headers.getFirst(TokenConstant.REQUEST_TYPE);
        gatewayLog.setReqType(requestType);

        Object startTime = exchange.getAttribute(GatewayConstant.GATEWAY_START_TIME);
        gatewayLog.setTime(ObjectUtil.isNotNull(startTime) ? System.currentTimeMillis() - Long.parseLong(startTime.toString()) : -1L);

        Object respData = exchange.getAttribute(GatewayConstant.GATEWAY_RESP_DATA);
        gatewayLog.setRespData(ObjectUtil.isNotNull(respData) ? respData.toString() : "");

        Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        gatewayLog.setRoute(route.toString());
        gatewayLog.setApiServiceName(route.getId());

        UserDetailX userInfo = getUserInfo(exchange);
        gatewayLog.setCreateUser(ObjectUtil.isNotNull(userInfo) ? userInfo.getUserId() : "");
        gatewayLog.setDataTenantId(ObjectUtil.isNotNull(userInfo) ? userInfo.getTenantId() : "");

        return gatewayLog;
    }

    /**
     * 通过网关交换机获取用户信息
     *
     * @param exchange 网关交换机
     * @return 用户信息
     */
    private UserDetailX getUserInfo(ServerWebExchange exchange) {
        String token = exchange.getRequest().getHeaders().getFirst(TokenConstant.ACCESS_TOKEN);
        return UserUtil.getLoginUser(token);
    }

}

